package com.xavier.dong.netty.groupchat;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author XavierDong
 **/
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {


    // 使用 一个 HashMap 管理
    private static Map<String, Channel> channels = new HashMap<>();
    private static Map<User, Channel> channels2 = new HashMap<>();


    // 定义 一个 Channel 组 管理 所有的 Channel
    // GlobalEventExecutor.INSTANCE 是 全局的事件执行器，是一个单例
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 表示 连接 建立，一旦 连接建立后，第一个被执行
     * <p>
     * 将 当前的 Channel 加入到 ChannelGroup 中
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        // 将 该 客户端的加入聊天的消息 推送给 其他在线的 客户端
        /**
         * 该 方法 会 将 ChannelGroup 中的 所有的 Channel 并发送 这个消息.
         * 我们不需要 自己 遍历
         */
        channelGroup.writeAndFlush("【客户端：】" + channel.remoteAddress() + " 加入聊天 " + FORMATTER.format(LocalDateTime.now()) + "\n");
        channelGroup.add(channel);

        channels.put("id100", channel);
        channels2.put(new User("1", "2222"), channel);
    }

    /**
     * 表示 Channel 处于 活动状态 ，提示 XXX 上线
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress() + " 上线了!");
    }


    /**
     * 当 Channel 处于 非 活动状态的提示哈，提示 XXX 离线
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress() + " 离线了!");
    }


    /**
     * 断开 连接 会被 触发 , 将 XXX 客户离开的信息 推送给 当前在线的 客户
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush("【客户端: " + channel.remoteAddress() + " 离开了" + FORMATTER.format(LocalDateTime.now()) + "\n");
        System.out.println("当前 ChannelGroup size=" + channelGroup.size());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {

        // 获取到 当前的 Channel 读取数据
        Channel channel = ctx.channel();

        // 这时 遍历 ChannelGroup，根据 不同的情况 回送不同的消息
        channelGroup.forEach(ch -> {
            if (ch != channel) {// 不是当前的 Channel ，转发消息
                ch.writeAndFlush("[客户]: " + channel.remoteAddress() + " 发送的消息： " + msg + "\n");
            } else
                // 回显自己发送的消息 给自己
                ch.writeAndFlush("[自己]发送了消息: " + msg + "\n");
        });

    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 关闭 通道
        ctx.close();
    }
}
